import { ElTree } from "element-plus";
import { Tree, TreeData, TreeOptions } from "./type";
import {
	RendererNode,
	RendererElement,
	createVNode,
	nextTick,
	VNode
} from "vue";
import {
	TreeKey,
	TreeNodeData
} from "element-plus/es/components/tree/src/tree.type";
import TreeBox from "./tree-box.vue";

export class BasicTree implements Tree {
	private treeOptions!: TreeOptions;
	private treeRef!: InstanceType<typeof ElTree> | null;
	constructor(option?: Partial<TreeOptions>) {
		this.treeOptions = {
			...{
				change() {},
				expand: false,
				lazy: false,
				nodeKey: "value",
				source: []
			},
			...(option || {})
		};
	}
	private init(treeRef: InstanceType<typeof ElTree> | null) {
		this.treeRef = treeRef;
	}
	setTreeSource(data: TreeData[]) {
		this.treeOptions.source = data;
	}
	getTreeSource(): TreeData[] {
		return this.treeOptions.source;
	}
	setTreeSelection(data: TreeKey[]): void {
		if (this.treeRef) {
			this.treeRef!.setCheckedKeys(data);
		} else {
			nextTick(() => this.treeRef?.setCheckedKeys(data));
		}
	}
	getTreeSelection(
		state: "Node" | "Keys" = "Keys"
	): (TreeNodeData | TreeKey)[] | [] {
		if (this.treeRef) {
			if (state === "Node")
				return this.filter(
					this.treeRef!.getCheckedNodes()
				) as TreeNodeData[];
			else
				return this.filter(this.treeRef!.getCheckedKeys()) as TreeKey[];
		} else {
			return [];
		}
	}
	setDisabled(id: TreeKey | TreeKey[], state: boolean = true): void {
		/** 循环查询 id 对应的 value 字段 */
		const setState = (
			id: string | number,
			state: boolean,
			list: TreeData[]
		) => {
			for (let node of list) {
				if (node.value === id) {
					node.disabled = state;
				}
				node.children?.length && setState(id, state, node.children);
			}
		};

		if (Array.isArray(id)) {
			id.forEach((d) => setState(d, state, this.treeOptions.source));
		} else {
			setState(id, state, this.treeOptions.source);
		}
	}
	getVNode(): VNode<RendererNode, RendererElement, { [key: string]: any }> {
		return createVNode(TreeBox, {
			configure: { ...this.treeOptions },
			init: this.init.bind(this)
		});
	}

	private filter(arr: any[]) {
		return arr.filter((item) => item && item !== 0);
	}
}
